package com.yupi.yupicturebackend.utils;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yupi.yupicturebackend.model.dto.picture.PictureQueryRequest;
import com.yupi.yupicturebackend.model.entity.Picture;
import com.yupi.yupicturebackend.model.vo.PictureVO;
import com.yupi.yupicturebackend.service.PictureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import cn.hutool.json.JSONUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TripleCacheUtil {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private PictureService pictureService;

    /**
     * 三级缓存获取分页数据
     * 1. 先查本地缓存(Caffeine)
     * 2. 再查Redis缓存
     * 3. 最后查数据库
     */
    public Page<PictureVO> getPicturesWithTripleCache(PictureQueryRequest queryRequest,
                                                      HttpServletRequest request) {
        // 构造缓存key
        String cacheKey = buildCacheKey(queryRequest);

        // 1. 先从本地缓存获取
        Page<PictureVO> result = getFromLocalCache(cacheKey);
        if (result != null) {
            log.info("从本地缓存获取数据: {}", cacheKey);
            return result;
        }

        // 2. 再从Redis缓存获取
        result = getFromRedisCache(cacheKey);
        if (result != null) {
            log.info("从Redis缓存获取数据: {}", cacheKey);
            return result;
        }

        // 3. 最后从数据库查询
        log.info("从数据库获取数据: {}", cacheKey);
        result = getFromDatabase(queryRequest, request);

        // 回填Redis和本地缓存
        if (result != null) {
            setToRedisCache(cacheKey, result);
            setToLocalCache(cacheKey, result);
        }

        return result;
    }

    /**
     * 从本地缓存获取
     */
    @Cacheable(value = "picturePage", key = "#cacheKey")
    public Page<PictureVO> getFromLocalCache(String cacheKey) {
        return null; // 由Spring Cache自动处理
    }

    /**
     * 从Redis缓存获取
     */
    public Page<PictureVO> getFromRedisCache(String cacheKey) {
        try {
            String json = redisTemplate.opsForValue().get(cacheKey);
            if (json != null) {
                return JSONUtil.toBean(json, Page.class);
            }
        } catch (Exception e) {
            log.error("从Redis获取缓存失败", e);
        }
        return null;
    }

    /**
     * 设置Redis缓存
     */
    public void setToRedisCache(String cacheKey, Page<PictureVO> data) {
        try {
            String json = JSONUtil.toJsonStr(data);
            redisTemplate.opsForValue().set(cacheKey, json, 5, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("设置Redis缓存失败", e);
        }
    }

    /**
     * 设置本地缓存（通过@Cacheable自动处理）
     */
    @Cacheable(value = "picturePage", key = "#cacheKey")
    public void setToLocalCache(String cacheKey, Page<PictureVO> data) {
        // 由Spring Cache自动处理
    }

    /**
     * 从数据库获取
     */
    public Page<PictureVO> getFromDatabase(PictureQueryRequest queryRequest,
                                           HttpServletRequest request) {
        long current = queryRequest.getCurrent();
        long size = queryRequest.getPageSize();

        // 查询数据库
        Page<Picture> picturePage = pictureService.page(new Page<>(current, size),
                pictureService.getQueryWrapper(queryRequest));

        // 获取封装类
        return pictureService.getPictureVOPage(picturePage, request);
    }

    /**
     * 构造缓存key
     */
    public String buildCacheKey(PictureQueryRequest queryRequest) {
        StringBuilder key = new StringBuilder("picture:page:");
        key.append(queryRequest.getCurrent()).append(":")
                .append(queryRequest.getPageSize());

        if (queryRequest.getUserId() != null) {
            key.append(":user:").append(queryRequest.getUserId());
        }

        if (queryRequest.getCategory() != null) {
            key.append(":category:").append(queryRequest.getCategory());
        }

        if (queryRequest.getTags() != null && !queryRequest.getTags().isEmpty()) {
            key.append(":tags:").append(String.join(",", queryRequest.getTags()));
        }

        if (queryRequest.getReviewStatus() != null) {
            key.append(":review:").append(queryRequest.getReviewStatus());
        }

        return key.toString();
    }
}
